<?php

/**
 * Compatibility for older versions of PHP
 * provides functions, tweaks and configs for compatibility
 * 
 * @author Sam-Mauris Yong <hellclanner at live dot com>
 * @license http://www.opensource.org/licenses/bsd-license New BSD License
 * @package Raise.Core
 * @since 1.2
 * @internal
 */

if(!function_exists('get_called_class')) {
    /**
     * get_called_class()
     * PHP 5 < 5.3.0
     * @return string
     * @link http://php.net/get-called-class
     * @internal
     */
    function get_called_class() {
        $matches = array();
        $bt = debug_backtrace();
        $l = 0;
        do {
            $l++;
            if(isset($bt[$l]['class']) && !empty($bt[$l]['class'])) {
                return $bt[$l]['class'];
            }
            $lines = file($bt[$l]['file']);
            $callerLine = $lines[$bt[$l]['line']-1];
            preg_match('/([a-zA-Z0-9\_]+)::' . $bt[$l]['function'] . '/', $callerLine, $matches);
            if (!isset($matches[1])){
                $matches[1] = NULL; //for notices
            }
            if ($matches[1] == 'self') {
                   $line = $bt[$l]['line'] - 1;
                   while ($line > 0 && strpos($lines[$line], 'class') === false) {
                       $line--;
                   }
                   preg_match('/class[\s]+(.+?)[\s]+/si', $lines[$line], $matches);
           }
        }
        while ($matches[1] == 'parent' && $matches[1]);
        return $matches[1];
    }
}

if(!function_exists('property_exists')){
    /**
     * Checks if the object or class has a property 
     * @param mixed $o The class name or an object of the class to test for 
     * @param string $property The name of the property 
     * @return boolean Returns TRUE if the property exists, FALSE if it doesn't exist or NULL in case of an error.
     * @link http://www.php.net/property-exists
     */
    function property_exists($o, $property){
        if (is_object($o)) {
            $v = get_object_vars($o);
        } else {
            $v = get_class_vars($o);
        }
        return array_key_exists($property, $v);
    }
}

if(!function_exists('str_ireplace')){
    /**
     * Case-insensitive version of str_replace()
     * PHP 4
     * @param string|array $search
     * @param string|array $replace
     * @param string|array $subject
     * @return string|array
     * @link http://php.net/str-ireplace
     * @internal
     */
    function str_ireplace($search, $replace, $subject){
        if(is_array($search)){
            array_walk($search, create_function('&$pat, $key', '$pat = \'\/\'\.preg_quote($pat, \'/\')\.\'\/i\';'));
        }else{
            $search = '/' . preg_quote($search, '/') . '/i';
        }
        return preg_replace($search, $replace, $subject);
    }
}

if(!function_exists("htmlspecialchars_decode")){
    /**
     * Convert special HTML entities back to characters
     * @param string $s
     * @param integer $quote_style (optional)
     * @return string
     * @link http://php.net/htmlspecialchars-decode
     */
    function htmlspecialchars_decode($s, $quote_style = ENT_COMPAT){
        return strtr($s, array_flip(get_html_translation_table(HTML_SPECIALCHARS, $quote_style)));
    }
}

if(!function_exists('getallheaders')){
    /**
     * Fetch all HTTP request headers
     * @return array
     * @link http://php.net/getallheaders
     * @internal
     */
    function getallheaders(){
        foreach($_SERVER as $h => $v){
            if(ereg('HTTP_(.+)', $h, $hp)){
                $headers[$hp[1]] = $v;
            }
        }
        return $headers;
    }
}


if(!function_exists('http_build_query')){
    /**
     * Generate URL-encoded query string
     * @param mixed $data
     * @param string $prefix (optional) 
     * @param string $sep (optional)
     * @param string $key (optional)
     * @return string
     * @link http://php.net/http-build-query
     * @internal
     */
    function http_build_query($data, $prefix = null, $sep = '', $key = ''){
        $ret = array();
        foreach((array)$data as $k => $v) {
            $k = urlencode($k);
            if(is_int($k) && $prefix != null) {
                $k = $prefix . $k;
            }
            if(!empty($key)){
                $k = $key . '[' . $k . ']';
            }
            if(is_array($v) || is_object($v)) {
                array_push($ret, http_build_query($v, '', $sep, $k));
            }else {
                array_push($ret,$k . '=' . urlencode($v));
            }
        }
        if(empty($sep)){
            $sep = ini_get('arg_separator.output');
        }
        return implode($sep, $ret);
    }
}

if(!function_exists('checkdnsrr') && strtoupper(substr(PHP_OS, 0, 3)) != 'WIN'){
    /**
     * Check DNS records corresponding to a given Internet host name or IP address
     * For support of the function on Windows. By HM2K (php@hm2k.org)
     * @param string $host may either be the IP address in dotted-quad notation or the host name.
     * @param string $type (optional) may be any one of: A, MX, NS, SOA, PTR, CNAME, AAAA, A6, SRV, NAPTR, TXT or ANY.
     * @return boolean
     * @internal
     */
    function checkdnsrr($host, $type = 'MX') {
        if (strtoupper(substr(PHP_OS, 0, 3)) != 'WIN'){
                return;
        }
        if (empty($host)) {
            return;
        }
        $types = array('A', 'MX', 'NS', 'SOA', 'PTR', 'CNAME', 'AAAA', 'A6', 'SRV', 'NAPTR', 'TXT', 'ANY');
        if (!in_array($type,$types)) {
            user_error('checkdnsrr() Type \'' . $type . '\' not supported', E_USER_WARNING);
            return;
        }
        @exec('nslookup -type=' . $type . ' ' . escapeshellcmd($host), $output);
        foreach($output as $line){
            if (preg_match('/^' . $host . '/', $line)) {
                return true;
            }
        }
    }
}

if(!function_exists('inet_pton')){
    /**
     * Converts a human readable IP address to its packed in_addr representation
     * @param string $ip A human readable IPv4 or IPv6 address.
     * @return string
     * @internal
     */
    function inet_pton($ip){
        if (strpos($ip, '.') !== false) {
            $ip = pack('N', ip2long($ip));
        }elseif (strpos($ip, ':') !== false) {
            $ip = explode(':', $ip);
            $res = str_pad('', (4*(8 - count($ip))), '0000', STR_PAD_LEFT);
            foreach ($ip as $seg) {
                $res .= str_pad($seg, 4, '0', STR_PAD_LEFT);
            }
            $ip = pack('H' . strlen($res), $res);
        }
        return $ip;
    }
}

if(!function_exists('inet_ntop')){
    /**
     * Converts a packed internet address to a human readable representation
     * @param string $ip
     * @return string
     * @internal
     */
    function inet_ntop($ip) {
        if (strlen($ip) == 4) {
            list(,$ip) = unpack('N', $ip);
            $ip = long2ip($ip);
        }elseif(strlen($ip) == 16){
            $ip = bin2hex($ip);
            $ip = substr(chunk_split($ip, 4, ':'), 0, -1);
            $ip = explode(':', $ip);
            $res = '';
            foreach($ip as $seg) {
                while($seg{0} == '0') $seg = substr($seg, 1);
                if ($seg != '') {
                    $res .= ($res == '' ? '' : ':') . $seg;
                } else {
                    if (strpos($res, '::') === false) {
                        if (substr($res, -1) == ':') continue;
                        $res .= ':';
                        continue;
                    }
                    $res .= ($res == '' ? '' : ':') . '0';
                }
            }
            $ip = $res;
        }
        return $ip;
    }
}

if(!function_exists('parse_ini_string')){
    /**
     * Parse a configuration string
     * @param string $ini The contents of the ini file being parsed.
     * @param boolean $process_sections By setting the process_sections  parameter to TRUE, you get a multidimensional array, with the section names and settings included. The default for process_sections is FALSE
     * @return array
     * @internal
     */
    function parse_ini_string($ini, $process_sections = false){
        $lines  = explode("\n", $ini);
        $return = array();
        $inSect = false;
        foreach($lines as $line){
            $line = trim($line);
            if(!$line || $line[0] == '#' || $line[0] == ';')
                continue;
            if($line[0] == '[' && $endIdx = strpos($line, ']')){
                $inSect = substr($line, 1, $endIdx-1);
                continue;
            }
            if(!strpos($line, '=')) // (We don't use "=== false" because value 0 is not valid as well)
                continue;

            $tmp = explode('=', $line, 2);
            if($process_sections && $inSect)
                $return[$inSect][trim($tmp[0])] = ltrim($tmp[1]);
            else
                $return[trim($tmp[0])] = ltrim($tmp[1]);
        }
        return $return;
    }
}